11. WateringService

Watering IntentService

In this exercise we will start by creating an IntentService class called PlantWateringService that extends from IntentService.

public class PlantWateringService extends IntentService

To keep things organized, it’s best to define the actions that the IntentService can handle, we will start by defining our first action as ACTION_WATER_PLANTS

public static final String ACTION_WATER_PLANTS =
                    "com.example.android.mygarden.action.water_plants";

Next we will create a static method called startActionWaterPlants that allows explicitly triggering the Service to perform this action, inside simply create an intent that refers to the same class and set the action to ACTION_WATER_PLANTS and call start service

public static void startActionWaterPlants(Context context) {
        Intent intent = new Intent(context, PlantWateringService.class);
        intent.setAction(ACTION_WATER_PLANTS);
        context.startService(intent);
    }

To handle this action we need to override onHandleIntent, where you can extract the action and handle each action type separately

@Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_WATER_PLANTS.equals(action)) {
                handleActionWaterPlants();
            }
        }
    }

Then finally we implement the handleActionWaterPlants method.
To water all plants we just run an update query setting the last watered time to now, but only for those plants that are still alive.
To check if a plant is still alive, you can compare the last watered time with the time now and if the difference is larger than MAX_AGE_WITHOUT_WATER, then the plant is dead!

private void handleActionWaterPlants() {
   Uri PLANTS_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_PLANTS).build();
   ContentValues contentValues = new ContentValues();
   long timeNow = System.currentTimeMillis();
   contentValues.put(PlantContract.PlantEntry.COLUMN_LAST_WATERED_TIME, timeNow);
   // Update only plants that are still alive
   getContentResolver().update(
      PLANTS_URI,
      contentValues,
      PlantContract.PlantEntry.COLUMN_LAST_WATERED_TIME+">?",
      new String[]{String.valueOf(timeNow - PlantUtils.MAX_AGE_WITHOUT_WATER)});
}

Now that we have our IntentService ready, let’s add the water drop image to our widget’s layout

<ImageView
        android:id="@+id/widget_water_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/water_drop_blue" />

Just like we did earlier, we need to create a PendingIntent to handle the click event on the water drop image, this time however launching a service instead of an activity

// Add the wateringservice click handler
Intent wateringIntent = new Intent(context, PlantWateringService.class);
wateringIntent.setAction(PlantWateringService.ACTION_WATER_PLANTS);
PendingIntent wateringPendingIntent = PendingIntent.getService(
                                             context, 
                                             0, 
                                             wateringIntent, 
                                             PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_water_button, wateringPendingIntent);